package mapproviderapi;

import java.util.ArrayList;
import java.util.List;


public class OpenStreetMapProvider extends MapProvider {
	
	protected final static String SERVER_URL = "http://tile.openstreetmap.org/";
	
	public OpenStreetMapProvider(int mapWidth, int mapHeight){
		super(mapWidth, mapHeight);
		tileHeight = 256;
		tileWidth = 256;
		maxZoom = 18;
	}
	
	/**
	 * 
	 * @param longitude
	 * @param zoom
	 * @return
	 */
	protected int getXTileNumber(double longitude, int zoom){
		return (int)Math.floor((longitude + 180) / 360 * (1 << zoom));		
	}
	
	/**
	 * 
	 * @param latitude
	 * @param zoom
	 * @return
	 */
	protected int getYTileNumber(double latitude, int zoom){		
		return (int)Math.floor((1 - Math.log(Math.tan(Math.toRadians(latitude)) + 
								1 / Math.cos(Math.toRadians(latitude))) / Math.PI) / 2 * (1 << zoom));		
	}
	
	/**
	 * 
	 * @param coordinate
	 * @param zoom
	 * @return
	 */
	protected MapTile getMapTile(Coordinate coordinate, int zoom){
		int xTile = getXTileNumber(coordinate.getLongitude(), zoom);
		int yTile = getYTileNumber(coordinate.getLatitude(), zoom);
		String tileUrl = SERVER_URL.concat(String.valueOf(zoom)).concat("/").concat(String.valueOf(xTile))
												.concat("/").concat(String.valueOf(yTile)).concat(".png"); 
		MapTile mapTile = new MapTile(coordinate, tileUrl, xTile, yTile, zoom);
		
		return mapTile;
	}
	
	protected MapTile getMapTile(int xTile, int yTile, int zoom){
		String tileUrl = SERVER_URL.concat(String.valueOf(zoom)).concat("/").concat(String.valueOf(xTile))
												.concat("/").concat(String.valueOf(yTile)).concat(".png");
		MapTile mapTile = new MapTile();
		mapTile.setTileUrl(tileUrl);
		mapTile.setTileHeight(tileHeight);
		mapTile.setTileWidth(tileWidth);
		
		return mapTile;
	}
	
	@Override
	public List<MapTile> getMapTiles(Coordinate center, int zoom) {
		int leftTileCenter = (int) Math.ceil(((double)mapWidth - tileWidth) / 2);
		int topTileCenter = (int) Math.ceil(((double)mapHeight - tileHeight) / 2);
		int dXTileNumber = (int) Math.ceil((double)leftTileCenter / tileWidth);
		int dYTileNumber = (int) Math.ceil((double)topTileCenter / tileHeight);
		int xTileCenter =  getXTileNumber(center.getLongitude(), zoom);
		int yTileCenter = getYTileNumber(center.getLatitude(), zoom);
		
		List<MapTile> listMapTile = new ArrayList<MapTile>();
		for (int yTile = - dYTileNumber; yTile <= dYTileNumber; yTile ++){
			for (int xTile = -dXTileNumber; xTile <= dXTileNumber; xTile ++){
				MapTile mapTile = getMapTile(xTile + xTileCenter, yTile + yTileCenter, zoom);
				mapTile.setLeft(xTile * tileWidth + leftTileCenter);
				mapTile.setTop(yTile * tileHeight + topTileCenter);
				listMapTile.add(mapTile);				
			}
		}
		
		return listMapTile; 
	}
	
}
